PowerShell脚本修改:按输入TXT文件名生成带日期的CSV
解决方案:按输入txt文件生成对应命名的CSV输出
以下是修改后的PowerShell脚本,实现每个输入txt文件对应一组带日期戳的CSV输出(用户角色、NSG规则、VM信息),文件名格式为[输入文件名前缀]_[数据类型]_[日期].csv:
$Folder = 'C:\Scrpting\Subscriptions' $OutputFolder = 'C:\Scrpting\Output' $dateStamp = (Get-Date).ToString("yyyyMMdd") # 确保输出文件夹存在,不存在则创建 if (-not (Test-Path -Path $OutputFolder)) { New-Item -Path $OutputFolder -ItemType Directory | Out-Null } # 逐个处理每个订阅txt文件 Get-ChildItem -Path $Folder -File -Filter "*.txt" | ForEach-Object { $currentFile = $_ $fileBaseName = $currentFile.BaseName # 提取文件名前缀(如ABC.txt -> ABC) # 读取当前文件中的订阅列表,过滤空行 $azSubs = Get-Content -Path $currentFile.FullName | Where-Object { $_ -match '\S' } # --- 1. 导出用户角色数据 --- $userRolesOutput = Join-Path $OutputFolder "$fileBaseName_UserRoles_$dateStamp.csv" $userRolesData = @() foreach ($azSub in $azSubs) { try { Set-AzContext -SubscriptionName $azSub -ErrorAction Stop | Out-Null $userRoles = Get-AzRoleAssignment | Where-Object { $_.ObjectType -eq "User" } foreach ($user in $userRoles) { $userRolesData += [PSCustomObject]@{ DisplayName = $user.DisplayName SignInName = $user.SignInName RoleDefinitionName = $user.RoleDefinitionName SubscriptionName = $azSub } } } catch { Write-Warning "处理订阅 $azSub 的用户角色时出错:$_" } } if ($userRolesData.Count -gt 0) { $userRolesData | Export-Csv -Path $userRolesOutput -NoTypeInformation -Force Write-Host "用户角色已导出:$userRolesOutput" } # --- 2. 导出NSG防火墙规则数据 --- $firewallOutput = Join-Path $OutputFolder "$fileBaseName_FirewallRules_$dateStamp.csv" $firewallData = @() foreach ($azSub in $azSubs) { try { Set-AzContext -SubscriptionName $azSub -ErrorAction Stop | Out-Null $azNsgs = Get-AzNetworkSecurityGroup foreach ($azNsg in $azNsgs) { $rules = Get-AzNetworkSecurityRuleConfig -NetworkSecurityGroup $azNsg | Select-Object ` @{label = 'NSG Name'; expression = { $azNsg.Name } }, ` @{label = 'NSG Location'; expression = { $azNsg.Location } }, ` @{label = 'Rule Name'; expression = { $_.Name } }, ` @{label = 'Source'; expression = { $_.SourceAddressPrefix } }, ` @{label = 'Source Application Security Group'; expression = { if ($_.SourceApplicationSecurityGroups) { $_.SourceApplicationSecurityGroups.id.Split('/')[-1] } else { $null } }}, ` @{label = 'Source Port Range'; expression = { $_.SourcePortRange } }, ` Access, Priority, Direction, ` @{label = 'Destination'; expression = { $_.DestinationAddressPrefix } }, ` @{label = 'Destination Application Security Group'; expression = { if ($_.DestinationApplicationSecurityGroups) { $_.DestinationApplicationSecurityGroups.id.Split('/')[-1] } else { $null } }}, ` @{label = 'Destination Port Range'; expression = { $_.DestinationPortRange } }, ` @{label = 'Resource Group Name'; expression = { $azNsg.ResourceGroupName } }, ` @{label = 'Subscription Name'; expression = { $azSub } } $firewallData += $rules } } catch { Write-Warning "处理订阅 $azSub 的NSG规则时出错:$_" } } if ($firewallData.Count -gt 0) { $firewallData | Export-Csv -Path $firewallOutput -NoTypeInformation -Force Write-Host "NSG规则已导出:$firewallOutput" } # --- 3. 导出VM信息数据 --- $vmOutput = Join-Path $OutputFolder "$fileBaseName_VMInfo_$dateStamp.csv" $vmData = @() foreach ($azSub in $azSubs) { try { Set-AzContext -SubscriptionName $azSub -ErrorAction Stop | Out-Null $vms = Get-AzVM $nics = Get-AzNetworkInterface | Where-Object { $_.VirtualMachine -ne $null } foreach ($nic in $nics) { $vm = $vms | Where-Object { $_.Id -eq $nic.VirtualMachine.id } if (-not $vm) { continue } # 获取公网IP(改用PowerShell cmdlet替代Azure CLI) $publicIP = (Get-AzPublicIpAddress | Where-Object { $_.Id -eq $nic.IpConfigurations.PublicIpAddress.Id }).IpAddress $vmData += [PSCustomObject]@{ VMName = $vm.Name ResourceGroupName = $vm.ResourceGroupName OS = $vm.StorageProfile.OsDisk.OsType PrivateIPAddress = $nic.IpConfigurations.PrivateIpAddress PublicIPAddress = if ($publicIP) { $publicIP } else { "Not Assigned" } SubscriptionID = (Get-AzContext).Subscription.Id Status = ((Get-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Status).Statuses[1]).code NICName = $nic.Name } } } catch { Write-Warning "处理订阅 $azSub 的VM信息时出错:$_" } } if ($vmData.Count -gt 0) { $vmData | Export-Csv -Path $vmOutput -NoTypeInformation -Force Write-Host "VM信息已导出:$vmOutput" } } Write-Host "所有文件处理完成"
关键修改说明
按单个txt文件独立处理
- 遍历每个输入txt文件,而非一次性读取所有订阅到统一列表
- 提取文件前缀(如
ABC.txt→ABC)作为输出文件名的一部分
生成对应命名的输出文件
每个输入文件会生成3个CSV,命名规则:[文件名前缀]_[数据类型]_[日期戳].csv
例:ABC_UserRoles_20240520.csv、ABC_FirewallRules_20240520.csv优化数据导出逻辑
- 先收集所有数据到数组,再一次性导出,避免多次
-Append导致的格式问题 - 添加
-NoTypeInformation移除CSV头部的类型信息,保持文件简洁 - 添加
-Force参数覆盖已存在的同名文件
- 先收集所有数据到数组,再一次性导出,避免多次
修复原脚本的问题
- 统一使用
Set-AzContext -SubscriptionName切换订阅(原脚本VM部分误用-SubscriptionID会报错) - 替换Azure CLI命令
Az vm list-ip-addresses为PowerShell cmdletGet-AzPublicIpAddress,保持脚本风格统一 - 修复
$subscriptionId未定义的问题,从当前上下文获取订阅ID - 添加空行过滤,跳过txt文件中的无效订阅条目
- 统一使用
增强健壮性
- 自动创建不存在的输出文件夹
- 加入
try/catch错误处理,输出警告信息并继续执行其他订阅 - 无数据时跳过导出,避免生成空文件
内容的提问来源于stack exchange,提问作者Saurabh
相关产品推荐
相关产品推荐

