Setup:
We are all in domain environment. Active Directory is Windows Server 2012 R2
Client Workstations are mix of Windows 10 versions (1703 and 1709)
Need to create user "Servis" on all workstation and place it to local Administrator group. I will input a text file with the host names.
This is the script im trying to make it work, but no success.
The user is created, but user is not added to local admin group.
This is the error i get :
Error creating Service23 on WinNT://WS-TEST: The following exception occurred while retrieving member "add": "The network path was not found.
$computers = Get-Content -path C:\Scripts\CreateLocalUser\New\Computers.txt
$username = "Servis"
$password = "P4$$w0rd!##"
Foreach ($computer in $computers) {
$users = $null
$computer = [ADSI]"WinNT://$computername"
Try {
$users = $computer.psbase.children | select -expand name
if ($users -like $username) {
Write-Host "$username already exists" -ForegroundColor Green
}
Else {
$user_obj = $computer.Create("user", "$username")
$user_obj.SetPassword($password)
$user_obj.SetInfo()
$user_obj.Put("description", "$username")
$user_obj.SetInfo()
$user_obj.psbase.invokeset("AccountDisabled", "False")
$user_obj.SetInfo()
$users = $computer.psbase.children | select -expand name
if ($users -like $username) {
Write-Host "$username has been created on $($computer.name)"
$group = [ADSI]("WinNT://" + $computername + "/administrators,group")
$group.add("WinNT://" + $computername + "/" + $username + ",user")
}
Else {
Write-Host "$username has not been created on $($computer.name)"
}
}
}
Catch {
Write-Host "Error creating $username on $($computer.path): $($Error[0].Exception.Message)"
}
}
Once you've defined your credential correctly with a password in a SecureString format creating a local admin is a 2 step process:
Create a user
Add that user to the Local Administrators group
These few lines are the powershell code needed:
$username = "Servis"
$password = ConvertTo-SecureString -AsPlainText "P4$$w0rd!##" -Force
New-LocalUser "$username" -Password $password -FullName "$username" -Description "Local admin $username"
Add-LocalGroupMember -Group "Administrators" -Member "$username"
If you want make you script more robust you should consider to create some Pester tests and add these checks to your script:
Validate if your file exists
Validate the content of the file (if is an IP or a FQDN with a regex)
Test if the host is reachable (e.g. Test-Connection -computername $computer -count 1 -quiet) before connecting
Using invoke-command with computername and argumentlist (username, password)
Check if the user was created successfully and is a member of the administrator group if not throwing an error
Write a log file to keep trace of all the tasks completed (by who, when on what host and so on).
I wrote a blog post on www.scriptinglibrary.com on few better ways of completing this task if you're interested.
Related
Hello dear community.
We got MS RDS Terminal Server and we would like to remove User Profile Disks for deleted and (maybe) disabled users.
I would like one script with following tasks:
Get all UPDs from path
Check UPD Owner
Check if the owner exist in AD and if is enabled
Remove UPD if owner not exist in ad or if is enabled
$updtest = Get-ChildItem -Path C:\updtest -Force
foreach($UPD in $updtest) {
##Get User Name
$UPD = $UPD.ToString()
$UPD = $UPD.Trim("UVHD-")
$UPD = $UPD.Trim(".vhdx")
$objSID = New-Object System.Security.Principal.SecurityIdentifier `
($UPD)
$objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
$userTest = $objUser.Value
$userTest = $userTest.Trim("Domain\")
$AdUser = [bool] (Get-ADUser -Filter {SamAccountName -eq $userTest })
if ($AdUser -eq $false) {Write-Host "User $userTest exist"}
else {Write-Host "User $AdUser exist"}
In step no. 3 is getting harder, because some users are not right trimmed (first letter missing). $UPD and $userTest have to be trimmed because Get-ADUser don't accept "DOMAIN" and New-Object System.Security.Principal.SecurityIdentifier don't accept ".vhdx" and "UVHD-"
Is there any another possibility to do easier this tasks?
It is possible to check if SID exists in AD without any conversion?
Thank you in advance!
I'm looking at creating a local administrator on a handful of machines (>30). I don't really want to use GPO if I can get away with it. LAPS is a little overkill for what I need.
I found a nice script online but it only creates the user and doesn't add them to the administrators group. Can anyone see the error?
#Define variables
$computers = Get-Content C:\Computers.txt
#$computers = Import-CSV C:\Computers.txt | select Computer
$username = "Admin"
$password = "Password99"
$fullname = "Admin"
$local_security_group = "Administrators"
$description = "Description"
Foreach ($computer in $computers) {
$users = $null
$comp = [ADSI]"WinNT://$computer"
#Check if username exists
Try {
$users = $comp.psbase.children | select -expand name
if ($users -like $username) {
Write-Host "$username already exists on $computer"
} else {
#Create the account
$user = $comp.Create("User", "$username")
$user.SetPassword("$password")
$user.Put("Description", "$description")
$user.Put("Fullname", "$fullname")
$user.SetInfo()
#Set password to never expire
#And set user cannot change password
$ADS_UF_DONT_EXPIRE_PASSWD = 0x10000
$ADS_UF_PASSWD_CANT_CHANGE = 0x40
$user.userflags = $ADS_UF_DONT_EXPIRE_PASSWD + $ADS_UF_PASSWD_CANT_CHANGE
$user.SetInfo()
#Add the account to the local admins group
$group = ([ADSI]"WinNT://$computer/$local_security_group,group")
$username = [ADSI]"WinNT://$Computer/$username,user"
#Validate whether user account has been created or not
$users = $comp.psbase.children | select -expand name
if ($users -like $username) {
Write-Host "$username has been created on $computer"
} else {
Write-Host "$username has not been created on $computer"
}
}
}
Catch {
Write-Host "Error creating $username on $($computer.path): $($Error[0].Exception.Message)"
}
}
In your code you are not actually adding the user to the group.
Here you are actually retrieving a group object, but you are not doing anything with it.
#Add the account to the local admins group
$group = ([ADSI]"WinNT://$computer/$local_security_group,group")
$username = [ADSI]"WinNT://$Computer/$username,user"
First you must remove the assignment to $username. Then you must invoke a method on the $group object to add the user:
#Add the account to the local admins group
$group = ([ADSI]"WinNT://$computer/$local_security_group,group")
$computerHostName = (Get-WmiObject -ComputerName $computer Win32_ComputerSystem).Name
$group.Add([ADSI]"WinNT://$computerHostName/$username,user")
There is a catch here. Notice I use Get-WmiObject to get the hostname from the computer. When using the Add() method, the computer name must be the unqualified hostname. For example server-01, and NOT server-01.domain.lan
If you want to retrieve the ADSI object for the user later, I recommend assigning it to a different variable name, like this:
$adsiUser = [ADSI]"WinNT://$Computer/$username,user"
UPDATE
I have successfully connected to Office 365 Admin service and Exchange Online Services. I have tested the cmdlets such as Get-MsolUser and they work fine. However, when I try to run the command Set-MsolUser to change the Title, I get the Access Denied error as shown below. It's weird because I can manually go into Exchange and change any property I want but it won't let me run this command? Any way around this?
Script to update Office 365 user attributes
## Variables
$systemmessagecolor = "cyan"
$processmessagecolor = "green"
$savedcreds=$false ## false = manually enter creds, True = from file
$credpath = "c:\downloads\tenant.xml" ## local file with credentials if required
## If you have running scripts that don't have a certificate, run this command once to disable that level of security
## set-executionpolicy -executionpolicy bypass -scope currentuser -force
Clear-Host
write-host -foregroundcolor $systemmessagecolor "Script started`n"
#install-module msonline
Import-Module -Name "C:\Temp\MsOnline" -Verbose
write-host -foregroundcolor green "MSOnline module loaded"
## Get tenant login credentials
$cred = Get-Credential
## Connect to Office 365 admin service
connect-msolservice -credential $cred
write-host -foregroundcolor $systemmessagecolor "Now connected to Office 365 Admin service"
## Start Exchange Online session
$EXOSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell -Credential $cred -Authentication Basic -AllowRedirection
import-PSSession $EXOSession -AllowClobber
write-host -foregroundcolor $processmessagecolor "Now connected to Exchange Online services`n"
write-host -foregroundcolor $systemmessagecolor "Script Completed`n"
# Load data from file.csv
$EXUsers = Import-csv file_path.csv
# Count variable for number of users update
$count = 0
# Go through each row that has user data in the CSV we just imported
ForEach($User in $EXUsers)
{
# Ppopulate hash table for Get-Msoluser splatting:
$GetParams =
#{
UserPrincipalName = $User.userPrincipalName
}
# Initialize hash table for Set-Msoluser splatting:
$SetParams =
#{
UserPrincipalName = $User.userPrincipalName
Title = $User.title
}
# Get user and update.
if ( Get-Msoluser #GetParams)
{
# Set User attributes
Set-MsolUser #SetParams
# Print that the user was updated
Write-Host -ForegroundColor Yellow "$User - User attributes have been updated."
# Update Count
$count += 1
}
}
# Print the number of updated users
Write-Host $count "Users have been updated" -ForegroundColor Green
Error message:
Set-Msoluser : Access Denied. You do not have permissions to call this cmdlet.
At line:1 char:59
+ ... ncipalName "name#company.com" | Set-Msoluser -Title "Test Title"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [Set-MsolUser], MicrosoftOnlineException
+ FullyQualifiedErrorId : Microsoft.Online.Administration.Automation.AccessDeniedException,Microsoft.Online.Administration.Automation.SetUser
SOLVED
The access denied issue was solve by running the script in Exchange Management Shell
Also these changes were made for the script to work properly:
principleUserName -> Identity
Get-MsolUser -> Get-Mailbox
Set-MsolUser -> Set-User
## Variables
$systemmessagecolor = "cyan"
$processmessagecolor = "green"
# Load data from file.csv
$EXUsers = Import-csv file_path.csv
# Count variable for number of users update
$count = 0
# Go through each row that has user data in the CSV we just imported
ForEach($User in $EXUsers)
{
# Ppopulate hash table for Get-Msoluser splatting:
$GetParams =
#{
Identity = $User.Identity
}
# Initialize hash table for Set-Msoluser splatting:
$SetParams =
#{
Identity = $User.Identity
Title = $User.Title
}
# Get user and update.
if ( Get-Mailbox #GetParams)
{
# Set User attributes
Set-User #SetParams
# Print that the user was updated
Write-Host -ForegroundColor Yellow "$User - User attributes have been updated."
# Update Count
$count += 1
}
}
# Print the number of updated users
Write-Host $count "Users have been updated" -ForegroundColor Green
I've recently created a little script that allows me to get the disk size and free space of 2 servers at each school site when I provide the script with the schools 4 digit site code.
First it pulls the information on the sites from a .csv file, and then uses that information to put together a string for the DC FQDN hostname, and the .10 server.
Then it requests the password for my elevated access account used to get the information on the disks.
I am having an issue where when the script creates the script block and then uses Invoke-Command and sends the script block to the servers, and provides back the PowerShell object with the information.
The error provided is as per below:
[{ServerName}] Connecting to remote server {ServerName} failed with the
following error message : WinRM cannot process the request. The following
error with errorcode 0x80090311 occurred while using Kerberos authentication:
There are currently no logon servers available to service the logon request.
Possible causes are:
-The user name or password specified are invalid.
-Kerberos is used when no authentication method and no user name are specified.
-Kerberos accepts domain user names, but not local user names.
-The Service Principal Name (SPN) for the remote computer name and port does
not exist.
-The client and remote computers are in different domains and there is no trust
between the two domains.
After checking for the above issues, try the following:
-Check the Event Viewer for events related to authentication.
-Change the authentication method; add the destination computer to the WinRM
TrustedHosts configuration setting or use HTTPS transport.
Note that computers in the TrustedHosts list might not be authenticated.
-For more information about WinRM configuration, run the following command:
winrm help config. For more information, see the about_Remote_Troubleshooting
Help topic.
+ CategoryInfo : OpenError: ({ServerName}:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : AuthenticationFailed,PSSessionStateBroken
Things I've tried:
Resetting my password
Altering the Authentication type to Basic
Getting others to try the same thing - some have the same issue, others do not
Other users on my workstations also have the same issue
I re-imaged my workstation and it worked for a bit, but then stopped again as it appeared to stop after the device installed software updates, so I'm in the middle of uninstalling those updates, however two of them won't allow me to uninstall, I assume they're forced installs by Microsoft and required to be installed (The uninstall button disappears when selected) - KB4019472 and KB4049065.
Device is running Windows 10 1607 v14393.1944, PowerShell v5.1.
There is a one-way trust between the domain I am in and the domains the DC1 and MS10 (.10) are in, the domains trust us, but we don't trust the domains.
The account I use is local admin on the device via a nested AD Group, across all domains.
I'm not very understanding of Kerberos, so any help would be amazing.
The script is below:
Note: I've had to remove some parts, so I've filled the area with what would be there (i.e. {String} where there would just be standard text, and {FQDNServerName} where there would be a FQDN server name written as text, or {Region} where I would have had the region written as text}).
$csvSchoolsLoc = "{FQDNServerName}\SharedReports$\SchoolsExport.csv"
$Schools = Import-Csv $csvSchoolsLoc -Delimiter "`t" -Header LocCode,SchoolName,SchoolAddress,SchoolPhoneNumber,SchoolFaxNumber,SchoolOfficerInCharge,DistrictCode,DistrictNumeric,RegionCode,RegionNumeric,LSD,WANLinkType,RouterName,RouterIP,RouterStatus,OneSchemaGraphUrl,OneSchemaSiteUrl,SCCMSiteID,SiteAdminNetwork,ProxyServerIP,PrimaryDcName,PrimaryDcIP,PrimaryDcOS,PrimaryDcVersion,PrimaryDcPatch,Style
#Gets the users credentials for their GBN ZZ account - this is used throughout the script for authentication
$username = "{Region}\zz-$env:USERNAME"
$mycreds = Get-Credential -UserName $username -Message "Enter your password for {region}\zz-$env:USERNAME"
Clear-Host
Write-Host "What is the schools 4 digit site code?" -ForegroundColor Magenta
$Global:SiteCode = Read-Host
Function Main {
Clear-Host
$SchoolName = $schools | Where-Object {$_.LocCode -eq $SiteCode} | ForEach-Object SchoolName
$Region = $schools | Where-Object {$_.LocCode -eq $SiteCode} | ForEach-Object RegionCode
Write-Host "Getting details for: " -ForegroundColor Gray -NoNewline; Write-Host "$SchoolName - $SiteCode - ($Region)"-ForegroundColor Yellow
$DC1 = "{String}$($Region)$($SiteCode)001.$region.{String}.{String}.{String}"
$MS10 = "{String}$($Region)$($SiteCode)010.$region.{String}.{String}.{String}"
if (Test-Connection -ComputerName $DC1 -Count 2 -Delay 1 -Quiet) {
$DC1Run = $true
} else {
$DC1Run = $false
}
if (Test-Connection -ComputerName $MS10 -Count 2 -Delay 1 -Quiet) {
$MS10Run = $true
} else {
$MS10Run = $false
}
$ScriptBlock = {
$DiskCTotal = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='C:'" -Impersonation 3 | ForEach-Object {$_.size / 1GB}
$DiskCFree = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='C:'" -Impersonation 3 | ForEach-Object {$_.freespace / 1GB}
$DiskZTotal = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='Z:'" -Impersonation 3 | ForEach-Object {$_.size / 1GB}
$DiskZFree = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='Z:'" -Impersonation 3 | ForEach-Object {$_.freespace / 1GB}
return #{
'ZFreeSpace' = $DiskZFree
'CFreeSpace' = $DiskCFree
'ZTotalSize' = $DiskZTotal
'CTotalSize' = $DiskCTotal
}
}
if (($DC1Run -eq $true) -and ($MS10Run -eq $true)) {
$ServerDC1 = Invoke-Command -ComputerName $DC1 -Credential $mycreds -ScriptBlock $ScriptBlock
$ServerMS10 = Invoke-Command -ComputerName $MS10 -Credential $mycreds -ScriptBlock $ScriptBlock
#Clear-Host
Write-Host -ForegroundColor Yellow "$SchoolName - $SiteCode - ($Region)"
Write-Host -ForegroundColor Cyan "Server $DC1 - Domain Controller"
Write-Host "$([math]::round($ServerDC1.CFreeSpace,2)) GB free on C Drive (Total Size $([math]::round($ServerDC1.CTotalSize,2)) GB)"
Write-Host "$([math]::round($ServerDC1.ZFreeSpace,2)) GB free on Z Drive (Total Size $([math]::round($ServerDC1.ZTotalSize,2)) GB)"
Write-Host ""
Write-Host -ForegroundColor Cyan "Server $MS10 - Distribution Point"
Write-Host "$([math]::round($ServerMS10.CFreeSpace,2)) GB free on C Drive (Total Size $([math]::round($ServerMS10.CTotalSize,2)) GB)"
Write-Host "$([math]::round($ServerMS10.ZFreeSpace,2)) GB free on Z Drive (Total Size $([math]::round($ServerMS10.ZTotalSize,2)) GB)"
} else {
#Clear-Host
Write-Host -ForegroundColor Yellow "$SchoolName - $SiteCode - ($Region)"
Write-Host -ForegroundColor Cyan "Server $DC1 - Domain Controller"
if ($DC1Run) {
Write-Host "DC1 connection status is running" -ForegroundColor Green
} else {
Write-Host "DC1 connection status is down" -ForegroundColor Red
}
Write-Host ""
Write-Host -ForegroundColor Cyan "Server $MS10 - Distribution Point"
if ($MS10Run) {
Write-Host "MS10 connection status is running" -ForegroundColor Green
} else {
Write-Host "MS10 connection status is down" -ForegroundColor Red
if ($DC1Run -eq $true) {
$RDP = Read-Host -Prompt "Would you like to RDP to $DC1 'Y'"
if ($RDP -eq "Y") {
Start-Process -FilePath "$env:windir\System32\mstsc.exe" -ArgumentList "/v:$DC1" -Wait -WindowStyle Maximized
}
}
}
}
Write-Host ""
Write-Host "What is the next schools 4 digit site code? -or- Press Enter to retry the above site again" -ForegroundColor Magenta
$Entry = Read-Host
if ($Entry -eq "") {
# Do nothing
} else {
$Global:SiteCode = $Entry
}
}
$x = 0
do {
Main
} until ($x -gt 0)
EDIT: The uninstall of the software updates did not fix the issue, so unless it's something to do with those 2 updates that I can't uninstall it doesn't appear to be Software Updates.
It turns out that the domains I am trying to reach were not in my TrustedHosts config for WinRM.
By using the following command, I was able to add the domains (of which I have numerous) to the TrustedHosts using the '*' wildcard.
NOTE: I have replaced part of the domain with {String} where it would normally have part of the domain name for confidentiality reasons.
winrm set winrm/config/client #{TrustedHosts="<local>,*.{string}.edu.au"}
I am trying to create user on remote machine using Powershell. Once account created I want to add that in local admin group.
Account is getting created but it is not getting added in admin group. Below is the code that I am using.
cls
$username = "test_user"
$password = "password"
$computer1 = hostname
$users = $null
$computer = [ADSI]“WinNT://$computer1”
Try {
$users = $computer.psbase.children | select -expand name
if ($users -like $username) {
Write-Host "$username already exists"
} Else {
$user_obj = $computer.Create(“user”, “$username”)
$user_obj.SetPassword($password)
$user_obj.SetInfo()
$user_obj.Put(“description”, “$username”)
$user_obj.SetInfo()
$user_obj.psbase.invokeset(“AccountDisabled”, “False”)
$user_obj.SetInfo()
$users = $computer.psbase.children | select -expand name
if ($users -like $username) {
Write-Host "$username has been created on $($computer.name)"
$group = [ADSI]("WinNT://"+$env:COMPUTERNAME+"/administrators,group")
$group.add("WinNT://$env:localhost/$username,user")
} Else {
Write-Host "$username has not been created on $($computer.name)"
}
}
} Catch {
Write-Host "Error creating $username on $($computer.path): $($Error[0].Exception.Message)"
}
What am I doing wrong?
$env:computername is your local computer. $env:localhost doesn't exist. $computer1 is the variable you defined of the computer to you are adding the user to earlier.
$group = [ADSI]("WinNT://$computer1/administrators,group")
$group.add("WinNT://$computer1/$username,user")
I use this
$computername = "computername" # place computername here for remote access
$username = 'user'
$password = 'P#ssw0rd1' #password
$desc = 'Local admin account'
$computer = [ADSI]"WinNT://$computername,computer"
$user = $computer.Create("user", $username)
$user.SetPassword($password)
$user.Setinfo()
$user.description = $desc
$user.setinfo()
$user.UserFlags = 65536
$user.SetInfo()
$group = [ADSI]("WinNT://$computername/administrators,group")
$group.add("WinNT://$username,user")
That is a whole lot of code, just to do this.
Invoke-Command -ComputerName SomeRemoteComputerName -ScriptBlock {
net user SomeNewUserName SomePassword
net localgroup administrators SomeNewUserName /add
}
Yeppers, I know, it's not all pure PoSH. Sure, you can do this with via more code in PoSH (way more in ), but sometimes you just need to get stuff done.
But vs doing this from scratch (well, unless you are just trying to learn stuff). There is a whole set of pre-built scripts and module for you to leverage. See:
'gallery.technet.microsoft.com/scriptcenter/site/search?f%5B0%5D.Type=RootCategory&f%5B0%5D.Value=localaccount'
Of course if all machines were on PoSH v5+, then you just use the built-in cmdlets for local user / group management.
'learn.microsoft.com/en-us/powershell/module/microsoft.powershell.localaccounts/?view=powershell-5.1'
As for the other question:
'check service account exist or not'
Assuming you are asking if this is for a remote computer, then it's the same approach.
Invoke-Command -ComputerName SomeRemoteComputerName -ScriptBlock {
Get-Service -Name SomeServiceName
Get-Service -DisplayName SomeServiceDisplayName
}