Windows 服务器迁移站点后,上传、下载、生成文件全部失效?一键修复 IIS 目录权限

前言

最近在进行 Windows 服务器迁移时,遇到了一个比较经典的问题。

将网站文件夹直接复制到新的服务器后,网站能够正常访问,但是很多功能全部失效,例如:

  • 文件上传失败

  • 文件下载失败

  • PDF、Excel、Zip 等文件无法生成

  • 日志无法写入

  • 图片无法保存

  • 临时文件创建失败

  • 删除文件时报 Access Denied

应用程序没有报编译错误,也没有出现 IIS 启动失败,而是在执行涉及文件操作时不断提示:

复制代码
Access to the path is denied.

或者

复制代码
UnauthorizedAccessException

又或者

复制代码
Access is denied.

排查了很久之后,最终发现原因其实非常简单。


问题原因

Windows 文件夹不仅仅包含文件内容,还包含 NTFS 权限(ACL)

如果网站目录采用下面几种方式迁移:

  • Windows 复制

  • WinSCP

  • FTP

  • 压缩包

  • Robocopy(未复制 ACL)

那么原来的 IIS 权限通常都会丢失。

例如:

复制代码
D:\Website\ProjectA

原服务器可能拥有:

复制代码
IIS AppPool\ProjectAPool

的修改权限(Modify)。

但是迁移到新服务器以后,只剩下:

复制代码
Administrators
SYSTEM
Users

而真正运行网站的 Application Pool 身份已经没有权限了。

因此:

  • 可以读取页面

  • 但是不能写文件

  • 不能删除文件

  • 不能创建目录

  • 不能上传文件

这就是为什么首页正常,但是上传下载全部失败。


为什么只影响上传下载?

因为 IIS 默认只需要读取网站文件即可。

例如:

复制代码
wwwroot
    index.html
    css
    js

浏览网页只需要:

复制代码
Read

权限即可。

但是上传文件时,需要:

复制代码
Modify

权限。

例如:

复制代码
wwwroot
    upload
        image.jpg

如果程序池账号没有 Modify 权限,就会直接失败。


手动修改权限的问题

当然,也可以手动修改。

例如:

右键文件夹

复制代码
属性
    安全
        编辑
            添加

输入:

复制代码
IIS AppPool\程序池名称

然后给予:

复制代码
Modify

权限即可。

但是如果服务器上有:

  • 十几个网站

  • 几十个网站

  • 上百个站点

一个一个添加权限显然效率太低。

于是可以利用 PowerShell 一次性完成。


PowerShell 自动修复所有 IIS 站点权限

下面这个脚本会:

  1. 自动读取所有 IIS Site

  2. 获取对应的 Application Pool

  3. 获取站点物理目录

  4. 为对应程序池账号授予 Modify 权限

  5. 自动递归到所有子目录

    Import-Module WebAdministration

    获取所有 Application Pool 名称

    $AppPools = Get-ChildItem IIS:\AppPools | Select-Object -ExpandProperty Name

    获取所有 Site

    $Sites = Get-Website

    foreach (Site in Sites)
    {
    PhysicalPath = Site.PhysicalPath

    复制代码
     if (-not (Test-Path $PhysicalPath))
     {
         Write-Host "Skip: $PhysicalPath"
         continue
     }
    
     Write-Host ""
     Write-Host "====================================="
     Write-Host "Site: $($Site.Name)"
     Write-Host "Path: $PhysicalPath"
    
     # 获取当前站点使用的程序池
     $Pool = $Site.applicationPool
    
     $Identity = "IIS AppPool\$Pool"
    
     Write-Host "Grant -> $Identity"
    
     icacls $PhysicalPath `
         /grant "$($Identity):(OI)(CI)M" `
         /T `
         /C `
         /Q
    
     Write-Host "Done."

    }

    Write-Host ""
    Write-Host "All IIS Sites Permission Updated."


脚本原理解析

1、获取所有 IIS 站点

复制代码
$Sites = Get-Website

等价于打开 IIS 管理器查看:

复制代码
Sites

中的所有网站。


2、获取站点物理目录

复制代码
$Site.PhysicalPath

例如:

复制代码
D:\Website\CRM

D:\Website\API

D:\Website\Admin

3、获取程序池名称

复制代码
$Pool = $Site.applicationPool

例如:

复制代码
CRMPool

ApiPool

AdminPool

4、拼接程序池身份

复制代码
$Identity = "IIS AppPool\$Pool"

最终得到:

复制代码
IIS AppPool\CRMPool

这是 IIS 应用程序真正运行时使用的身份。


5、授予 Modify 权限

复制代码
icacls $PhysicalPath `
    /grant "$($Identity):(OI)(CI)M"

其中:

参数 说明
OI Object Inherit,文件继承
CI Container Inherit,目录继承
M Modify(修改权限)

因此:

复制代码
(OI)(CI)M

表示:

当前目录及所有子目录、文件都授予 Modify 权限。


6、递归所有子目录

复制代码
/T

表示:

复制代码
Recursive

递归整个目录树。

否则只会修改根目录。


7、忽略错误继续执行

复制代码
/C

即使某个目录权限修改失败,也不会中断整个脚本。

例如:

复制代码
Site1 成功

Site2 成功

Site3 失败

Site4 继续执行

非常适合批量修复。


8、静默输出

复制代码
/Q

关闭 icacls 的详细输出。

控制台只保留脚本中输出的日志,更清晰易读。


如何运行脚本

  1. 使用管理员身份启动 Windows PowerShell

  2. 将上述脚本保存为 Grant-IISPermissions.ps1

  3. 如系统限制脚本执行,可临时执行:

    Set-ExecutionPolicy RemoteSigned -Scope Process

  4. 运行脚本:

    .\Grant-IISPermissions.ps1

执行完成后,将看到类似输出:

复制代码
=====================================
Site: CRM
Path: D:\Website\CRM
Grant -> IIS AppPool\CRMPool
Done.

=====================================
Site: API
Path: D:\Website\API
Grant -> IIS AppPool\ApiPool
Done.

All IIS Sites Permission Updated.

修复完成后建议验证

建议重点验证以下功能是否恢复正常:

  • 文件上传

  • 文件下载

  • 图片保存

  • PDF 导出

  • Excel 导出

  • ZIP 压缩生成

  • 日志写入

  • 临时文件创建

  • 删除或覆盖文件

如果上述功能均恢复正常,基本可以确认问题由目录权限缺失导致。


总结

Windows 服务器迁移站点后,网站能够访问但上传、下载、导出等涉及文件写入的功能异常 ,大多数情况下都是 IIS 应用程序池账号缺少目标目录的 NTFS Modify 权限所致。

相比逐个站点手动配置权限,本文提供的 PowerShell 脚本能够自动遍历所有 IIS 网站,为对应的应用程序池授予正确的目录权限,特别适用于多站点服务器迁移后的批量修复场景。

建议在每次完成网站迁移后,将此脚本作为标准运维检查项执行一次,可以有效避免因权限问题导致的各类线上故障。

相关推荐
时光书签4 个月前
了解脚本语言
python·bash·batch命令
看海的四叔5 个月前
【Linux】命令行常规操作全攻略:入门+实战+速查
linux·运维·github·命令行·batch命令
Kang.Charles5 个月前
bat提升管理员权限执行命令行
batch命令
吳所畏惧1 年前
NVM踩坑实录:配置了npm的阿里云cdn之后,下载nodejs老版本(如:12.18.4)时,报404异常,下载失败的问题解决
前端·windows·阿里云·npm·node.js·batch命令
乌云暮年1 年前
Git简单命令
git·gitee·github·batch命令
stormsha1 年前
Linux中su与sudo命令的区别:权限管理的关键差异解析
linux·运维·服务器·鸿蒙系统·ux·batch命令
dudly1 年前
用Python打造自己的专属命令行工具
开发语言·python·batch命令
ew452182 年前
【JAVA】bat批处理命令启动jar包
java·pycharm·jar·batch命令
Pfolg2 年前
定时关机(python)
windows·python·batch命令·定时关机