Modify Active Directory Client OU from Client Machine - powershell

I am trying to create a powershell startup script for my domain controlled computers that will place the computer into the the specified OU. I would like for the variables to be taken on the local computer and then passed to the remote server. Once there I would like to execute the last two lines on the server.
The script below does work if it is ran on the server however as stated above I would like to be able to execute this from a client machine. How can I make this happen?
$computername = $env:ComputerName
$new_ou = "OU=TestOU,DC=Test,DC=Controller,DC=com"
Import-Module ActiveDirectory
Get-ADComputer $computername | Move-ADObject -TargetPath $new_ou
Note: Before anyone asks...my goal is to have the OU be determined by the client IP address. I understand that there are scripts that will do the discribed above but they run strictly on the server and query the DNS. I would rather have this run as a startup script on the local computer so I an better control which computers are being moved. At this point I am not interested in tackling this issue. Only the issue of how to execute the above lines on a local machine.

I assume you want to run the last 2 lines on the server because you expect that most of your domain computers won't have the RSAT tools or AD cmdlets installed.
The way to run it on a server is to have PowerShell Remoting enabled on the server and then use Invoke-Command.
That authentication is typically done with kerberos, though you could change the method, and you can supply credentials manually (though I doubt you want to be embedding credentials in the script).
You need to consider that the user making the AD changes needs permission to do so. Usually that's a domain admin, although permission could be delegated.
If you're running this as a startup script, it's running as SYSTEM. That account authenticates on the domain as the computer account (COMPUTERNAME$). This means that the computer account needs permission to move itself, which may mean it needs the ability to write objects into all possible OUs (I don't recall offhand which permissions are needed).
So you would either need to grant this ability to all computers (any computer in Domain Computers would have the ability to move any other computer to any OU), or somehow give each computer only the ability to move itself into the correct OU (which might still be too much in the way of permissions).
Another option is to make a customized session configuration on the server with a RunAs user. You could limit the users allowed to connect to the session (to Domain Computers), and limit the allowed commands so that the connecting computers can only run a limited set of functions/cmdlets. Even better, you can write your own function to do the change and only let them run that one. With the RunAs user being a privileged user in AD, the changes will work without the connecting user having the ability to make the changes directly, and without giving the connecting user the ability to use the privileged user or elevate their own permission. Remember that the connecting user in this case is the computer account.
This last method is, I think, the best/most secure way to do what you want, if you insist that it must be initiated from the client machine.
Reconsider doing this as a server-side process. Get-ADComputer can return an IPv4 address for the object, so you could use that instead of DNS. Centralizing it would make it easier to manage and troubleshoot the process.

Related

New-CimSession without elevation by providing admin credentials on Windows 10?

I need to query some WMI values using PowerShell from Windows 10 devices. The script is executed in the context of a non-admin user by some software distribution tooling.
There is a local admin account, and for the current purpose (retrieving information before wiping the system) it wouldn't be a problem to put the password in the script. As automation is a hard requirement, there is no way to deal with UAC windows or the user to enter some credentials.
Is there any way to get
$sess = New-CimSession -Credential $admincred
to work without running into Access is denied, because it isn't run in an elevated context? Can I somehow self-elevate it by just having the admin credentials?
[Edit]
The comments asked to provide more concrete information:
I want to onboard many unmanaged (i.e. no software distribution tool, no domain join) Windows 10 devices to Windows Autopilot.
The devices are not at a specific site.
The device vendor can't provide the information.
The users don't have administrative privileges
The users don't know the local admin password (I do)
Exposing the local admin password is less of a problem than the missing tech knowledge of the users (the password is considered legacy)
The firewall is preventing incoming traffic (no RDP, WinRM)
Code (Source):
$devDetail = (Get-CimInstance -CimSession $session -Namespace root/cimv2/mdm/dmmap -Class MDM_DevDetail_Ext01 -Filter "InstanceID='Ext' AND ParentID='./DevDetail'")
It is too time consuming to get the information using manual remote sessions with a tool like Teamviewer. Getting the users to download a tool from the intranet and running it would be a way to go. So I created a standalone application that builds and runs a customized PowerShell script. What won't work is getting it to run in an elevated session. I always end up with Access denied.
Can I somehow self-elevate it by just having the admin credentials?
No you cannot. UAC is designed to prevent exactly what you are trying to do. Related Q&A:
elevate without prompt - verb runas start-process
UAC Getting in the Way of EXE Install Powershell
Powershell provide credentials for RunAs
There may be many workarounds, but they all will have in common that you have to go to your machines (locally or remotely) at least once, gain administrative privileges and prepare something, e. g.:
A scheduled task that runs under your local administrator account or under SYSTEM and triggers the execution of your script
Disabling UAC (temporarily) (not recommended either way)
Installing any remote management software, services or accounts (with extra run as background job privilege)

Accessing files over the network through a script running as NT Authority\System

I'm not sure if I am asking this in the right spot or not, sorry if I am wrong.
I would like to know please, SCCM is currently operational in our school, and we use it to install software across our network.
I have a piece of software that requires a different channel for each room or staff laptop that it is installed in.
I have managed to set up a powershell script that polls a csv for the channel that should be assigned to each room, and when the script it run, it pulls that channel and installs the software with that channel assigned.
What I am having trouble with now, is that SCCM installs the software using the local system account, and the csv is located on a network share.
When the System account goes to poll the csv file it gets an access denied error, even though System has full control of the csv and directory that the csv is located in.
Is it just me not understanding the permissions that System has, or can System not interact with other devices over the network, I assumed that being system on both devices, it would be able to cross to another device and impersonate system on that device.
Is there a way around this?
Thanks for any feedback.
The system account uses the machine account when accessing the network e.g. COMPNAME$, if you're on AD you can add a grant to that computer account to the file share ACL. If you don't have a domain you can create a local account with matching username and password on both machines and configure the service to run as that account.
By simply adding Domain Computers to the files permissions list and assigning it Read/Write permissions, I am able to let any computer in this group (all computers on the domain) access the specific files.
This is also what Andy Arismendi was saying, however just an already setup group.

How to find out the Exchange server name from within standard PowerShell (not EMS)?

Let's say I would like to check some user mailbox properties from within PowerShell. I can run the script in Exchange Management Shell but the problem is that I have no guarantee that the end user will be running the script directly on Exchange or a machine with any Exchange tools. So, I can tell the end user to just run the script in the PowerShell (not EMS) and encode importing pssesion into the script.
However, here comes the main problem of mine, I cannot hard-code the server name into the script (it will be used in many different environments) and I would like to avoid asking the end user to provide the Exchange Server name for the pssesion.
Is there any way to obtain the Exchange Server name automatically with just vanilla PowerShell (no EMS, etc.)? The script will be ran by users with domain admin privileges, most likely there will be no Outlook on the machines (so no MAPI profiles configuration), if that is of any help.
I'm not sure how portable this is (it works on my E2K7 setup, but your mileage may vary)...
You can look in AD to get a list of exchange servers by doing something like the following:
$exchangeServers = [ADSI]"LDAP://contoso.com/CN=Exchange Servers,OU=Microsoft Exchange Security Groups,DC=contoso,DC=com"
$exchangeServers.Member
In my environment, this lists all of the exchange server computer accounts, plus a few other groups, but it's a starting point.

Remote location: no access, or does not exist/offline?

I'm making a PowerShell script that will allow the user to move certain local files to a certain server. To ease the process I want to check if the user has access to the server or not, and if not, I want to prompt for a username/password.
Using Test-Path I can check whether or not the user can access specific remote location. However, if Test-Path fails, there is no way of knowing if it's because the remote location does not exist, or because the user does not have sufficient rights.
I'm looking for a way to:
Find out if the user has access to a remote location (could use Test-Path for this)
(if above failed) Find out if this is because the remote location is unavailable or because the user does not have sufficient rights
(depending on above) Show error message or prompt for credentials
Of course I could Test-Path, ask for credentials if necessary, and then Test-Path again. But I'm trying to find a nicer solution.
You can use Test-Connection to see if the server exists. This is not a fool-proof method though because not all servers and other devices that may be in the network path respond to ICMP requests, which is what Test-Connection and ping use.

Running a cgi perl script as an Administrator

I'm writing a perl script for a website, and I need to be able to control VirtualBox via the website. I'm not sure where to start, or if I'm even trying to debug in the right area, but here goes.
My server is running IIS7 on Windows Server 2008 R2. I'm also running 2 virtual machines through the vboxmanage command line interface. These VMs are running under SERVER\administrator.
When I open my website, it requests a login. I login to the website as SERVER\administrator and click a link that calls my script using an xmlhttprequest. Now, normally, it doesn't matter what user I run these as, but with vboxmanage, if I run the command as a different user, the list of VMs is different. I tried whoami, which returned SERVER\administrator, but %DOMAINNAME%\%USERNAME% returns the domain that the server is connected to as dommainname and SERVER$ as the username. The vboxmanage command then fails.
On the website, impersonation is turned on. When I turn impersonation off, the whoami request changes to be iis apppool\website. Any ideas on how to get around this?
As a final note, I've thought about using runas, but since it prompts for a password, there's no way to call it through scripting (and that would be a poor security decision, I'd imagine).
This is an oft recurring, well-known and well-solved problem. Instead of having one big program dealing with requests from the Web and managing the VM (strong coupling), separate the concern and write two programs, each doing exactly one task.
The user facing program running in the Web server context can continue with limited privileges. The VM manager is a stand-alone program running with the necessary admin privileges, either repeatedly from the scheduler or as daemon/service.
Have the first communicate with the second over a message-queue.