I am having trouble getting an array passed to a scriptblock in Start-Job. Can you tell me what I might be doing wrong?
$bounceBlock = {
param(
[string[]]$list,
[System.Management.Automation.PSCredential]$cred
)
Add-PSSnapin VMware.VimAutomation.Core | Out-Null
Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -Scope User -InvalidCertificateAction Ignore -Confirm:$false | Out-Null
Connect-VIServer -Server servername -Credential $cred -AllLinked
Get-VM -Name $list
}
if ($targets) {
$activeTargets = $targets | Get-Random -Count $prodTargets.Count
$counter = [pscustomobject] #{Value = 0}
$groupSize = 50
$groups = $activeTargets | Group-Object -Property {[math]::Floor($counter.Value++ / $groupSize)}
$connection = Connect-VIServer -Server servername -Credential $cred -AllLinked
if ($connection -match "servername") {
foreach ($group in $groups) {
while ((Get-Job -State Running).Count -ge 5) {
Start-Sleep -Seconds 5
}
Start-Job -ScriptBlock $bounceBlock -ArgumentList (,$group.Group.ServerName),$cred
}
Disconnect-VIServer * -Force -Confirm:$false
}
}
I basically split an array into chunks of 50 (working) then try to run them as jobs. The error I get looks like it's trying to run Get-VM for a single server, named all 50 values appended together.
I am certainly no expert with PS, but first to address how you're passing in the appended list of servers; I do something similar with Azure VMs using Get-AzureVM and I pass in my list of VM names in a System.Array to functions or cmdlets such as a variable such as $theVMs= "MyServer1","MyServer2","MyServer3"
and then I execute a foreach loop over ($vm in $theVMs) and then perform the actions such as Get-VM sequentially. I do this sequentially since PS has some much lower limits, 5 per my experience, doing this via a parallel for loop.
A typical way I interact with the VMs remotely and create a PS Job per each is to use
$uri = Get-AzureWinRMUri -ServiceName $svc -Name $vmname
Invoke-Command -ConnectionUri $uri -Credential $creds **-JobName
$jobname**
-ArgumentList $vmname -ScriptBlock {
param([string]$thevm) ...
}
This requires the InstallWinRMCertAzureVM.ps1 script which is discussed and available at http://blogs.technet.com . I use this for between 30 servers regularly.
Just wanted everyone to know in case they run into a similar problem, this is an issue with running Get-VM, and it exists whether running it in a job or workflow. VMWare is aware of this issue.
Related
I have created a tsv file to list Servers and Services as follows:
TSV File as follows:
Hostname Services
=========================
Server01 SP4AdminV4,SPTraceV4,SPWriterV4,WAS,W3SVC
Server02 SP4AdminV4,SPTraceV4,SPWriterV4,WAS,W3SVC,SPSearchHostController, OSearch16
PowerShell command
Import-csv C:\ServerServerList.tsv
$Services = $_.Services -Split ','
Start-Service -Computer 'Server01' -Name $Services
I then get the following error:
Start-Service: Cannot Bind Argument to parameter 'Name' because it is an empty string.
At Line:3 char:43
+ Start-Service -Computer $_.Hostname -Name **$Services**
+
+categoryinfo: InvalidData (:) [Start-Service], ParameterBindingValidationException
+FullyQualifiedErrorId: ParameterArgumentValidationErrorEmptyStringNotAllowed,
Microsoft.Powershell.Commands.StartServiceCommand
There are a couple of problems I can spot at a glance. First you don't seem to be assigning $Services correctly. 2nd you Start-Service doesn't have a -ComputerName parameter.
To get around that you can use the use Get-Service in conjunction with Set-Service implicitly using the -InputObject parameter via the pipeline.
Import-csv C:\ServerServerList.tsv -Delimiter "`t" |
ForEach-Object{
$Services = $_.Services -Split ','
Get-Service -Computer $_.HostName -Name $Services
} |
Start-Service
I'm assuming this is a Tab separated file as you described. Also assuming the services are listed in such a way to make the split proper.
The loop sends [System.ServiceProcess.ServiceController] objects down the pipeline. Those are bound to the -InputObject parameter. Internally Start-Service uses the .MachineName property to make the change on the remote system.
Warning: Get/Set-Service doesn't always report errors properly in this kind of scenario. The primary obstacle I've encountered is misleading errors and/or silent failures in cases where the operator account doesn't have access to the remote system.
I'm sure there's easier ways to go about this but, here's what I got:
# import csv and save to variable.
$CSV = Import-Csv -Path 'C:\ServerServerList.tsv'
# Use a foreach loop to iterate throw csv
# one row at a time - assigning the current iteration to $Row.
foreach ($Row in $CSV) {
# Split services into an array
$Services = ($Row.Services -split ',').Trim()
# Invoke the start-service call due to it not
# having it's own -ComputerName parameter to work with.+
Invoke-Command -ScriptBlock {
# Start the service using the newly created array of $Services.
# Note: we must use a *Remote Variable* to pass over our local variable
# by specifying the $using: keyword.
Start-Service -Name $using:Services -PassThru -WhatIf
} -ComputerName $Row.Hostname
}
- This is untested -
I've been lurking around grabbing code answers from this site for years, but this is my first time actually asking a question. I don't actually get paid to code, rather I use scripts to make routine tasks easier.
I've been using a powershell script with the following code (that I pretty much gleaned from this site) to gather disk usage on client servers:
$dataColl = #()#Makes an array, or a collection to hold all the object of the same fields
foreach ($serverName in (get-content c:\reporting\Disk_useage\My_servers.txt))
{
$path = “\\$serverName\d$\folder1\TargetSubdir“
$dirSize = Get-ChildItem $path -recurse -force | select Length |Measure-Object -Sum length
$dirSize.sum = $dirSize.sum/1MB
$finalResult = “{0:N2} MB” -f $dirsize.sum
$dataObject = New-Object PSObject
Add-Member -inputObject $dataObject -memberType NoteProperty -name “ServerName” -value $serverName
Add-Member -inputObject $dataObject -memberType NoteProperty -name “Dir_Size” -value $finalResult
$dataColl += $dataObject
$dataObject
}
$dataColl | Export-Csv -noTypeInformation -path c:\reporting\Disk_useage\Svr_disk.csv
This has been working fine, but we now have a 2nd domain with client servers, so I need to add credentials for servers in the 2nd domain. I've been researching ways to pass credentials along, and got this bit of code (PW has been stored already in the .TXT file):
$username = "MyDomain\MyAccount"
$password = cat C:\reporting\securestring.txt | convertto-securestring
$cred = new-object -typename System.Management.Automation.PSCredential `
-argumentlist $username, $password
But I'm supposed to add these parameters somewhere to actually USE the credentials that have been set up:
-Authentication default -Credential $Cred
I've tried it in several different spots without success. FYI, the list in My_servers.txt has a bunch of servers I DON'T need credentials for (since they're on the current domain), and a bunch of servers where I DO need credentials (because they're on another domain). But the credentials I'm using for the script are for a service account that exists in both domains with the same ID/PW. Any help in sorting this out would be greatly appreciated.
Adil's suggestion in code would be:
$dataColl = #()#Makes an array, or a collection to hold all the object of the same fields
$username = "MyDomain\MyAccount"
$password = Get-Content C:\reporting\securestring.txt | convertto-securestring
$cred = New-Object -typename System.Management.Automation.PSCredential `
-argumentlist $username, $password
foreach ($serverName in (get-content c:\reporting\Disk_useage\My_servers.txt))
{
$dirSize = Invoke-Command -Credential $cred -ComputerName $serverName -ScriptBlock {
Get-ChildItem “d:\folder1\TargetSubdir“ -recurse -force | select Length | Measure-Object -Sum length
}
$dirSize.sum = $dirSize.sum/1MB
$finalResult = “{0:N2} MB” -f $dirsize.sum
$dataObject = New-Object PSObject
Add-Member -inputObject $dataObject -memberType NoteProperty -name “ServerName” -value $serverName
Add-Member -inputObject $dataObject -memberType NoteProperty -name “Dir_Size” -value $finalResult
$dataColl += $dataObject
$dataObject
}
$dataColl | Export-Csv -noTypeInformation -path c:\reporting\Disk_useage\Svr_disk.csv
I am very new to Powershell and in learning stage, I have tried to create an script to do automate below task. This script is not working as i am expected. Could you please review it and give me some help on it.
My task is,
I am trying to find out SQL Services (more than one SQL services in multiple servers) which are in stopped state and trying to start it, Waiting for an minute to complete the service start and verifying the service status again. If still it is stopped state i am trying to sending an email to setup of people for an action.
Could you please review the below code and correct the mistake, i tried to find it but unable to do
#Define servers & Services Variables
$Servers = GC "E:\Bhanu\SQLServer.txt"
$Services = GC "E:\Bhanu\SQLService.txt"
#Function Call
Function ServiceStatus ($Servers, $Services)
{
foreach ($Server in $Servers)
{
foreach ($Service in $Services)
{
$Servicestatus = get-service -ComputerName $Server -Name $Service
if ($Servicestatus.Status -eq "Stopped")
{
Start-service $Service
Start-Sleep -Seconds 60
$ServiceStatus1 = Get-Service -ComputerName $Server -Name $Service
if ($Servicestatus1.Status -eq "Stopped")
{
FuncMail -To “abc#gmail.com” -From “abc#gmail.com” -Subject $Server + $Service "fails to Start, Take immediate Action to avoid Impact” -Body $ServiceName "Service fails to Start, Take immediate Action to avoid Impact” -smtpServer “servername”
}
}
}
}
}
function FuncMail
{
#param($strTo, $strFrom, $strSubject, $strBody, $smtpServer)
param($To, $From, $Subject, $Body, $smtpServer)
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = $From
$msg.To.Add($To)
$msg.Subject = $Subject
$msg.IsBodyHtml = 1
$msg.Body = $Body
$smtp.Send($msg)
}
servicestatus $Servers $Services
Please let me know if you need anything here from my end
Hi this isn't the best approach and i'm doing it in quick way.
note %=foreach-object; ?=Where-Object.
You have to save your password on one file if your smtp-server require authentication otherwise don't run it using read-host -assecurestring | convertfrom-securestring | out-file "C:\Secure\Password.txt"
I'm also assuming you have your servers saved on one file.
My solution is to start all sql server service if you want to start specific just save the service name on one file on separate line.
The code to execute bellow.
#Loading Server and service details
$Services=Get-content C:\PS\Service.txt
$servidores=get-content C:\PS\Servers\Servers.txt
#Loading Mail credential
$Mailpasswordpath="C:\PS\Securestring.txt"
$Mailusername="DOmain\User"
$password=cat $Mailpasswordpath |ConvertTo-Securestring
$Cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Mailusername,$password
$servidores|Foreach-Object{Get-Service -ComputerName $_ -Name $Services }| #Get the services running on all servers
Where-Object{$_.Status -eq "Stopped"}| #Which status is equal stopped
Foreach-Object{
$_.Start(); #try to start
Start-Sleep -Seconds 60; #wait one minute
$_.Refresh(); #refresh then service to update status
#validate is status still stopped
if($_.Status -eq "Stopped")
{
#LOADING Mail details
$To="user#domain.com"
$subject="$($_.MachineName) $($_.Name) fails to Start, Take immediate Action to avoid Impact"
$From="ServiceStatus#domain.com"
$smtp="Server.domain.com"
$body="$($_.Name) Service fails to Start, Take immediate Action to avoid Impact"
#Sending email to notify
Send-MailMessage -To $To -Subject $subject -From $From -SmtpServer $smtp -Body $body -Credential $Cred
}
}
P.S: It's not the best approach I only decide to solve this problem. if you want we can create a function together later just test it first.
param(
[string]$UserName
)
$DCs = Get-ADGroupMember "Domain Controllers"
foreach ($DC in $DCs)
{
Write-Host $DC.name
}
$EventList = Get-Eventlog –ComputerName $ComputerName -LogName Security -InstanceID 4740 -UserName *Username* -After "07/20/2014"
$EventList | Format-List -Property TimeGenerated,Message
I'm writing a script to figure out lockout events for specific users within all the domains.
I'm trying to figure out how to the computername variable from the $DC.name, I know at some point i'll have to move the $Eventlist = Get-Eventlog line within the loop.Then would I just delete the write-host $DC.name?
Get-EventLog can take an array of computernames. You don't even need the foreach loop. So what you could do is this:
$DCs = Get-ADGroupMember "Domain Controllers"
$EventList = Get-Eventlog –ComputerName $DCs.Name -LogName Security -InstanceID 4740 -UserName *Username* -After "07/20/2014"
$EventList | Format-List -Property TimeGenerated,Message
Note that you should only use Format-List if you do not intend to use the information for anything other than displaying in the console. If you want to use the object for anything, don't use Format-List or Format-Table.
When trying to create users from a file I get an error when -otherAttributes #{} is added to ps script. I am new to powershell and can not get it to work. Any guidance is appreciated. This is My code:
Import-Module ActiveDirectory
$OU = 'ou=Staging OU, dc=Domain, dc=net'
$usrfile = "\\servername\testuser.csv"
Import-Csv $usrfile |
ForEach-Object {
New-ADUser -SamAccountName $_.samaccountname -UserPrincipalName $_.Userprincipalname -Name $_.Name -DisplayName $_.displayname -GivenName $_.givenname -Surname $_.sn -Initials $_.initials -Title $_.title -OtherName $_.middlename `
-Description $_.description -Department $_.department -EmployeeID $_.employeeid -Path $OU -Country $_.c `
-OtherAttributes #{departmentNumber=$user.departmentnumber;localeID=$user.localid;extensionAttribute1=$user.extensionAttribute1;employeeType=$user.employeetype} `
-AccountPassword (ConvertTo-SecureString "Password" -AsPlainText -Force) -Enabled $true `
-PasswordNeverExpires $false -ChangePasswordAtLogon $true -PassThru
} > Import.log
The parameter "-otherAttributes #{}" fails in my AD. I found other way change this value in AD.
Try with this:
PS> Set-ADuser -identity joseiba -Clear 'msRTCSIP-PrimaryUserAddress'
PS> Set-ADuser -identity joseiba -Add #{'msRTCSIP-PrimaryUserAddress'='4213#grupofibratel.com'}
BR
Make sure you have all your $'s as $_... when accessing the object in the current loop iteration. I see some aren't.
you left out your ' around the ldapdisplayname for the otherattributes
#{departmentNumber=$user.departmentnumber;
should be: #{'departmentNumber'=$user.departmentnumber;
you need the ' around each ldapdisplayname in otherattributes..
just fought this myself dealing with the notes field