TrimStart / ForEach在多行上

时间:2014-01-08 19:36:22

标签: powershell

我是学习PowerShell的新手,我一直在编写代码来执行以下操作:

  1. 从CSV文件导入计算机列表
  2. 将计算机从文件中的旧名称重命名为文件
  3. 中的新名称
  4. 在已重命名的每台计算机上抓取当前登录的用户
  5. 修剪用户名的开头部分(“CompanyName \”)
  6. 将“@ company.com”添加到该行的末尾
  7. 将该数据设置为变量
  8. 将该变量用作程序化电子邮件中的电子邮件地址
  9. 发送电子邮件
  10. 现在,我输出了4&的结果。 5到文本文件,然后通过 Get-Content 导入它,但这不起作用,好像该文件尚不存在,它将无法正常工作。它似乎无法输出文件然后从中获取内容。我认为必须有某种方法来做,但我不确定。

    我认为我没有正确循环 TrimStart For-Each 命令。任何帮助将不胜感激。

    $Cred = Get-Credential
    $Import = Import-CSV Rename.csv -Header OldName, NewName
        ForEach ( $Machine in $Import ) {Rename-Computer -ComputerName $Machine.OldName -NewName $Machine.NewName -DomainCredential $Cred -whatif -Verbose}
    $a = ForEach ( $User in $MachineList ){
        (Get-WmiObject -ComputerName $User.OldName -Namespace root\cimv2 -Class Win32_ComputerSystem)[0].UserName;
        }
    $b = $a.TrimStart("CompanyName\") | ForEach {$_+'@Company.com'} | Out-File names.txt
    $Address = Get-Content names.txt 
    ForEach ($line in $Address) {
        $Outlook = New-Object -ComObject Outlook.Application
        $Mail = $Outlook.CreateItem(0)
        $Mail.To = "$Address"
        $Mail.Subject = "Please restart your computer"
        $Mail.HTMLBody = Get-Content RenameComputerEmail.htm
        $Mail.Send()
        }
    

2 个答案:

答案 0 :(得分:1)

我不确定为什么Out-File不起作用,但我建议采用类似下面的方法。请注意,之前我没有使用outlook.application,因此我无法保证代码无需调整即可使用。

$Cred = Get-Credential
$Import = Import-CSV Rename.csv -Header OldName, NewName

$Addresses = @()

#Rename each computer and get the username
ForEach ( $Machine in $Import ) {
    $Comp = Get-WmiObject -ComputerName $User.OldName -Class "Win32_ComputerSystem"
    $Usermail = "$($Comp.UserName.Split("\")[-1])@Company.com"
    $Addresses += $Usermail

    Rename-Computer -ComputerName $Machine.OldName -NewName $Machine.NewName -DomainCredential $Cred -whatif -Verbose
    #Don't bother saving the names and then reloading. (unless it's for logging)
} 

#Create one instance of outlook
$Outlook = New-Object -ComObject Outlook.Application

#Send mails to each address
ForEach ($address in $Addresses) {
    $Mail = $Outlook.CreateItem(0)
    $Mail.To = "$address"
    $Mail.Subject = "Please restart your computer"
    $Mail.HTMLBody = (Get-Content RenameComputerEmail.htm) -join "`n"
    $Mail.Send()
}

#Disposing the outlook object using all the methods just to be safe.
$Outlook.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Mail)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Outlook)

答案 1 :(得分:1)

我有一些建议可以帮助你编写脚本。

变量命名

尝试将变量命名为自我描述的东西。当您逐行调试和逐步执行代码时,这将使故障排除变得更容易。

编写代码

逐步编写代码。不要试图一次咬太多。如果您使用内嵌注释记录代码,将有助于您更有意义。

参数名称

每次编写脚本时都使用参数名称,并且不要将位置参数视为理所当然。这将提高脚本的可读性。

文件系统路径

限定所有文件系统路径。您永远不知道“工作目录”何时可能与脚本所在的目录不同。使用$PSScriptRoot变量(首先在PowerShell v3.0中引入)来引用“包含脚本文件的文件夹。

解决方案

我之前没有测试过这段代码,因为我没有CSV文件的副本,但它应该可以帮助您了解更多内容。我也冒昧地整合了一些代码以使其更简单。

重要:确保您运行的是最新版本的PowerShell,即版本4.0。 3.0将是一个可接受的替代方案,但就功能而言,任何比这更大的东西都是相当严格的。您可以通过键入$PSVersionTable来确定您正在运行的版本。

#requires -version 3.0

# 1. Get administrative credential
$Cred = Get-Credential;

# 2. Import the CSV file
$Import = Import-CSV -Path $PSScriptRoot\Rename.csv -Header OldName, NewName;

# 3. Rename each computer
$Import | % { Rename-Computer -ComputerName $PSItem.OldName -NewName $PSItem.NewName -DomainCredential $Cred -WhatIf -Verbose; };

# 4. Get username from each, remote computer, and write to names.txt
$Import.OldName | ForEach-Object -Process { (Get-WmiObject -ComputerName $PSItem -Namespace root\cimv2 -Class Win32_ComputerSystem).UserName.TrimStart('CompanyName\') + '@companyname.com'; } | Out-File -FilePath $PSScriptRoot\names.txt;

# 5. Get all of the usernames
$Address = Get-Content -Path $PSScriptRoot\names.txt;

# 6. Send e-mail to each user
$Outlook = New-Object -ComObject Outlook.Application;
ForEach ($line in $Address) {
    $Mail = $Outlook.CreateItem(0)
    $Mail.To = "$Address"
    $Mail.Subject = "Please restart your computer"
    $Mail.HTMLBody = Get-Content RenameComputerEmail.htm
    $Mail.Send()
    }