Capture multiple variables - powershell

I currently have a powershell script that allows me to enter in the details for users one at a time which can then be used as variables later on. At present the script calls for each input and then saves for as a variable, this is then repeated 10 times.
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') | Out-Null
$NameOne = [Microsoft.VisualBasic.Interaction]::InputBox("Enter UserName")
$firstname,$surname = $NameOne -split("\.")
$NameTwo = [Microsoft.VisualBasic.Interaction]::InputBox("Enter UserName")
$firstname,$surname = $NameTwo -split("\.")
Is there a way to shorten the script to both allow usernames to be input and stored but to also move on to the next part of the script when an InputBox has no data input?
Thanks
Tom

Use a while loop:
$Users = while(($Username = [Microsoft.VisualBasic.Interaction]::InputBox("Enter UserName")).Trim() -ne "")
{
$firstname,$surname = $Username -split '\.'
New-Object psobject -Property #{
Firstname = $firstname
Surname = $surname
Username = $Username
}
}
When the user inputs nothing or whitespace, the loop will exit, otherwise it'll create a new "User object" that will end up in the $Users array

Related

SMLETS: Powershell

We want to generate an SR per row based on the criteria of a CSV file looking like:
SR templete
The additional criterion:
If the SLO countdown is less than 7 days then the due date is always 7 days for the ticket to be due. Otherwise then then countdown is number SLO _Countdown
The support group is always servicedesk
Unless the host_name does not contain "RES" then it is the support group is EITS_HW_Notes and it will be assigned to "custodian".
No matter what an SR is generated even if null.
My difficulty is my lack familiarity with smlets. I am happy to consider generating tickets via email as well. But would like help on how best to do that via powershell. But the code I came up with is below:
`#Prod
#$GLOBAL:smdefaultcomputer = "prodserver"
#Test
$GLOBAL:smdefaultcomputer = "testserver"
Import-Module SMlets
$path = "C:\Temp\Test.csv"
$csv = Import-csv -path $path
#Variable / Class Setup
$srClass = Get-SCSMClass -name System.WorkItem.ServiceRequest
$srprior = Get-SCSMEnumeration -Name ServiceRequestPriorityEnum.Medium
$srurg = Get-SCSMEnumeration -Name ServiceRequestUrgencyEnum.Medium
#$ararea = get-SCSMEnumeration -Name ServiceRequestAreaEnum.Other
$ararea = get-SCSMEnumeration -Name Enum.add3768303064ec18890170ba33cffda
$title = “Title Goes Here”
$descrip = "Description info goes here"
#Service Request Arguements
$srargs = #{
Title = $title;
Urgency = $srurg;
Priority = $srprior;
ID = “SR{0}”;
Area = $ararea;
SupportGroup = "ServiceDesk";
Description = $descrip
}
#Create Service Request
$newServiceRequest = New-SCSMOBject -Class $srClass -PropertyHashtable $srargs -PassThru
#get SR ID of the new object
$SRId = $newServiceRequest.id
#Get Projection & Object for Created Service Request
$srTypeProjection = Get-SCSMTypeProjection -name System.WorkItem.ServiceRequestProjection$
$SRProj = Get-scsmobjectprojection -ProjectionName $srTypeProjection.Name -filter “Id -eq $SRId”
#Set Afffected User
$userClass = Get-SCSMClass -Name Microsoft.AD.UserBase$
$cType = "Microsoft.EnterpriseManagement.Common.EnterpriseManagementObjectCriteria"
$cString = "UserName = 'itservicenotifications' and Domain = 'SHERMAN'"
$crit = new-object $cType $cString,$userClass
$user = Get-SCSMObject -criteria $crit
$AffectedUserRel = get-scsmrelationshipclass -name System.WorkItemAffectedUser$
New-SCSMRelationshipObject -RelationShip $AffectedUserRel -Source $newServiceRequest -Target $user -Bulk`
I tried the above code but am running into issues recognizing the column name in the CSV file and am unfamiliar with SMLETS + powershell if statements.
Columns are:
CSV Columns
CSV text with examples is: Columns with examples
Could you paste the CSV columns as text, please? Or, better, a sample CSV with one or two rows (redact any sensitive data).
I would expect a CSV to contain multiple rows - even if yours does not, it's good defensive programming to act as if it does. So the first modification I suggest is:
$path = "C:\Temp\Test.csv"
$csv = Import-csv -path $path
foreach ($Row in $csv)
{
# the rest of your code goes in here
}
I find it helpful while debugging to go step-by-step. If I understand your problem right, it's about building the right hashtable in $srargs to pass to New-SCSMOBject. So the next modification is:
foreach ($Row in $csv)
{
$srClass = Get-SCSMClass -name System.WorkItem.ServiceRequest
# etc
$srargs = #{
Title = $title
Urgency = $srurg
Priority = $srprior
ID = “SR{0}”
Area = $ararea
SupportGroup = "ServiceDesk"
Description = $descrip
}
$srargs # write the hashtable so you can inspect it
# skip the rest of the code for now
}
I understand your question as "how to express the logic of":
support group is always servicedesk
Unless the host_name does not contain "RES"
then the support group is contents of EITS_HW_Notes cell in CSV
and it will be assigned to "custodian"
I can't help you with setting the assignee. But we can rejig the rest of the statement:
if host_name contains "RES"
SupportGroup = servicedesk
else
SupportGroup = contents of EITS_HW_Notes cell
You can code that like this:
foreach ($Row in $csv)
{
$srClass = Get-SCSMClass -name System.WorkItem.ServiceRequest
# etc
if ($Row.host_name -like "*RES*")
{
$SupportGroup = "ServiceDesk"
}
else
{
$SupportGroup = $Row.EITS_HW_Notes
}
$srargs = #{
Title = $title
# etc
SupportGroup = $SupportGroup
Description = $descrip
}
}
Does that get you any closer to your solution?

Powershell CSV Variable Issue

I am having a problem with passing a variable into a CSV. I need to pass an email for a spreadsheet showing all skills. It's the same email for each skill. I just want the $email to populate my csv. It does not pass and only shows the $email instead of the test#test.com in the column.
I am new at powershell so any guidance is greatly appreciated. Thank you.
------------here is my script-------------------------
Add-Content -Path C:\temp\test.csv -Value '"User Name","Skill Name","Level"'
$Email = "test#test.com"
$agent = #(
}
'"$Email","T1","4"'
'"$Email","T2","6"'
'"$Email","T3","7"'
'"$Email","Training","1"'
'"$Email","Supervisor","8"'
)
$agent | foreach { Add-Content -Path C:\temp\temp.csv -Value $_ }
Because you are new to Powershell, I'm showing you two alternative ways of framing the problem. These might help you get used to some of the features of powershell.
$Email = 'test#test.com'
$mytext = #"
"User Name","Skill Name","Level"
"$Email","T1","4"
"$Email","T2","6"
"$Email","T3","7"
"$Email","Training","1"
"$Email","Supervisor","8"
"#
$mytext | Out-file Mycsv.csv
Here, I just set up the Email variable, then create one big here string with the header and the five data records in it. Because I used double quotes on the here string, the variable $Email will be detected inside of it. A here string with single quotes would not have behaved correctly.
Then, I pass $mytext through a pipeline one line at a time, and Out-file collects all this into a file.
Here's the second approach:
$Email = 'test#test.com'
$myarray = #(
[PsCustomobject]#{"User Name" = $Email; "Skill Name" = "T1"; "Level" = 4}
[PsCustomobject]#{"User Name" = $Email; "Skill Name" = "T2"; "Level" = 6}
[PsCustomobject]#{"User Name" = $Email; "Skill Name" = "T3"; "Level" = 7}
[PsCustomobject]#{"User Name" = $Email; "Skill Name" = "Training"; "Level" = 1}
[PsCustomobject]#{"User Name" = $Email; "Skill Name" = "Supervisor"; "Level" = 8}
)
$myarray | Export-Csv myothercsv.csv
Here, I set up the variable Email, then create an array of custom objects, each with the same named properties.
Then I pass the array through a pipeline to Export-Csv which converts everything to Csv format. It's worth noting that Export-Csv V5 throws in a line that says #TYPE in it. This is not hard to eliminate, using the notype parameter if desired. It's also worth noting that the double quotes in the output file were all added in by Export-csv, and weren't copies of the double quotes in the script.
Edit. Pipelines are a surprisingly easy and flexible way of getting things done in powershell. For this reason, cmdlets like Out-File and Export-Csv are built to work well with pipelines supplying a stream of input. A lot of loop control, initialization, and finalization busy work is being handled behind the scenes by PS.

Powershell returns output too late\ at wrong position

I'm writing a simple script which displays a menu where one can choose from various scripts. One of those scripts should return the location which got a user account locked.
The script I want to use is this one here:
https://gallery.technet.microsoft.com/scriptcenter/Get-LockedOutLocation-b2fd0cab
I added three lines to the end of the script so that I can read the output before the window gets closed:
$username = Read-Host 'Please enter a username'
Get-LockoutLocation -Identity $username
Read-Host 'Press a key to quit'
The script gets executed with this command:
start powershell -ArgumentList '.\get-lockout-location.ps1'
When I execute the script it first returns the domain controller which locked the account. However the next thing which appears is the line which asks for a key press to quit. And at the end comes the output from the event log.
Does someone know what I have to change so that the key press lines is the last thing that appears? I tried already quite a lot of things (executing from a different file, piping the output, removing the process part, putting the Read-Host line to a different position)and none of it worked.
This happens because the author of that script forces formatting on the first set of output, but not the second.
Change the last Foreach() loop to:
$Events = Foreach($Event in $LockedOutEvents)
{
If($Event | Where {$_.Properties[2].value -match $UserInfo.SID.Value})
{
$Event | Select-Object -Property #(
#{Label = 'User'; Expression = {$_.Properties[0].Value}}
#{Label = 'DomainController'; Expression = {$_.MachineName}}
#{Label = 'EventId'; Expression = {$_.Id}}
#{Label = 'LockedOutTimeStamp'; Expression = {$_.TimeCreated}}
#{Label = 'Message'; Expression = {$_.Message -split "`r" | Select -First 1}}
#{Label = 'LockedOutLocation'; Expression = {$_.Properties[1].Value}}
)
}#end ifevent
}#end foreach lockedout event
$Events |Format-List

AD user creation with SamAccountName availability check loop

I'm learning Powershell by making a script that will hopefully automate everything that needs to be done when we get a new hire or a consultant. Currently I'm working on the part that will create the AD account. Below are the variables specific to this portion of the script.
#Variables for preliminary SamAccountName, modifiers and initials array
$PrelSamAccountName = ("se" + [string]$GivenName.Substring(0,3) + [string]$SurName.Substring(0,3)).ToLower()
$Modifier1 = 1
$Modifier2 = 0
$InitialsArray = #("x","y","z")
Here is the loop. I cut out a bunch of parameters on New-ADUser to make it less cluttered.
try {
#Checks if preliminary SamAccountName is taken or not
$ADCheck = Get-ADUser -Filter {SamAccountName -eq $PrelSamAccountName}
#Creates new user
New-ADUser -Name $Name -SamAccountName $PrelSamAccountName
} catch {
#Replaces final character in preliminary SamAccountName with "1++"
while (($ADCheck | Select-Object -ExpandProperty SamAccountName) -eq $PrelSamAccountName) {
$PrelSamAccountName = ([string]$PrelSamAccountName.Substring(0,7) + ($Modifier1++)).ToLower()
}
#Changes $Initials from $null to x/y/z if an existing user has identical name as new user
while (($ADCheck | Select-Object -ExpandProperty Name) -eq $Name) {
$Initials = $InitialsArray[$Modifier2++]
$Name = $GivenName + " " + $Initials + " " + $SurName
}
}
Everything is working as intended, except for the fact that a new user is created every other time I run the loop. Ideally I would want it to create a new user every time it is run. :)
I'm assuming it has something to do with the placement of the $ADCheck variable, but after having rewritten this portion multiple times I simply can't get it to work. Any ideas?
Thanks in advance.
You have some logical problems in here:
Follow this Approach:
Pseudocode:
while (user exist) {create new username}
new-aduser new username
PS Code:
function new-sam
{
#creates new sam
}
$sam = "username"
$a=$false
while (!$a)
{
try {
$a = [bool](Get-ADUser -Identity $sam )
}
catch {
$a = $false; $sam = new-sam
}
}
new-aduser ....

Changing user properties in powershell

I have a script that creates a user and assigns the password and the user to a group but I need to get 2 check boxes ticked - 'User cannot change password' and 'Password never expires' but for the life of me I cannot find out how to do this.
My script so far is this:-
# Create User and add to IGNITEWEBUSERS Group
$user = $domain
# If more then 15 chars trim to just 15 chars
$user = $user.substring(0, 15)
$user = $user + "_web"
# Generate Random Complex Password
# Generate a password with 2 non-alphanumeric character.
$Length = 10
$Assembly = Add-Type -AssemblyName System.Web
$RandomComplexPassword = [System.Web.Security.Membership]::GeneratePassword($Length,2)
$password = $RandomComplexPassword
$group = 'IGNITEWEBUSERS'
$objOu = [ADSI]"WinNT://$computer"
$objUser = $objOU.Create("User", $user)
$objUser.setpassword($password)
$objUser.SetInfo()
$objUser.description = $domain + " IIS User"
$objUser.SetInfo()
$OBjOU = [ADSI]"WinNT://$computer/$group,group"
$OBjOU.Add("WinNT://$computer/$user")
That works and does what it should do but anyone know how I can set those 2 check boxes?
Various threads suggest something similar to Set-ADUser -CannotChangePassword:$true but am not using Active Directory and this doesn't work.
Your advice appreciated
Paul
Got it figured out this morning:-
$objUser.UserFlags = 64 + 65536 # ADS_UF_PASSWD_CANT_CHANGE + ADS_UF_DONT_EXPIRE_PASSWD
Set the useraccountcontrol property. You can find a list of useraccountcontrol flags here: http://support.microsoft.com/kb/305144
Add the values of the flags you want (NORMAL_ACCOUNT = 512, PASSWD_CANT_CHANGE = 64, DONT_EXPIRE_PASSWORD = 65536) for a total of 66112, and set the property to that number:
$obUser.useraccountcontrol = 66112
BTW, you only need to call the SetInfo() method once at the end, after setting all the properties you want to set.
Use WMI to get the user account:
# Use this filter so WMI doesn't spend forever talking to domain controllers.
$user = Get-WmiObject Win32_UserAccount -Filter ("Domain='{0}' and Name='{1}'" -f $env:ComputerName,$Username)
$user.PasswordChangeable = $false
$user.PasswordExpires = $false
$user.Put()