PowerShell Connecting To Office 365 from Module - powershell

I have created a PowerShell Module. Each function in the module has it's own script file so I can keep track of them.
I have a problem with the function below:
function Connect-O365
{
$global:o365Cred = Get-Credential
$global:o365Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell -Credential $global:o365Cred -Authentication Basic -AllowRedirection -Verbose
Import-PSSession $global:o365Session -Verbose -AllowClobber
Connect-MsolService –Credential $global:o365Cred -Verbose
Get-Mailbox # SEE BELOW
}
When I call the function it goes through all the motions and appears to run correctly. No errors are shown. However when I call teh get-mailbox function I get an error that the 'command or cmdlet does not exist'.
If I execute each line of code on the command line it works fine. If I add the function to my PowerShell profile it also works fine. I also added the Get-Mailbox line to the end of it (as next to the comment # SEE BELOW) and it displays the mailboxes.
What it looks like to me is something to do with scope. As soon as this is put into a module function it stops working as it should. As soon as it runs and exits the commands that I'm needing disappear.
I have tried making the function global but that doesn't work either.
Does anybody have any suggestions?

Related

Why does importing my custom modul show the whole script code?

The Problem:
I have a big custom modul with tons of functions. I import it via my profile.ps1 file like this:
import-module "\\server\path\Filename.psm1"
This worked perfectly in the past.
But since today I added in new code to my profile.ps1 code.
What I changed was that I create a 2nd session to Office 365.
The whole ps1 file looks like this now:
# Log Files
Start-Transcript
# Session leeren
Get-PSSession | Remove-PSSession
#Session auf onPrem
$onpremSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://onPremServer/powershell
Import-PSSession $onpremSession -Prefix onPremises
#Session auf Cloud
$cloudSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential "$env:USERNAME#mycompany.com" -Authentication Basic -AllowRedirection
Import-PSSession $cloudSession -Prefix Cloud
#Modul Import von allen Scripts
import-module "\\server\path\Filename.psm1"
# Show available CMDlets
get-commands
So since today when I start my powershell using this profile.ps, powershell loads in, creates the session and then when it jumps to the import-module line it shows the whole code from my custom modul.
Screenshot:
Why? I already tried to add a -Verbose:$false but that doesn't change anything.
How can I get rid of the whole script block it shows from the custom modul?
I solved it by saving the import-PsSession output into a variable like this: $s = Import-PSSession $onpremSession -Prefix onPremises
This gets rid of the output.

PowerShell returning a PSSession object

I'm new to PowerShell and trying to write some Exchange Online modular scripts for various tasks. The model I'm working on is to have a control script that calls other parameterised scripts to perform reusable functions.
I've written a connection script, but when I return the PSSession object to my command script I can't import the session, it is somehow getting cast to an object.
How should I be sharing this session around my scripts?
Control script:
$session = .\Connection.ps1 -user admin#mydomain.com
Import-PSSession $session
Connection script (summary):
Param (
[string]$userparam
)
$UserCredential = Get-Credential -userName $userparam
$Exch = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
return $Exch
First, this is happening because when you run a script it runs in its own scope. You'll get the return value as an object, but it won't be "live" anymore because the scope in which it was created doesn't exist.
Second, it sounds an awful lot like what you really want is a module. Write these pieces as functions, not scripts, and then make them into a single package by writing them as a module.
Doing so would solve your scope problem as well, but the advantages are many.

Import-PSSession fails in script, works in shell

I'm new to Powershell scripting and I'm working on a user management Powershell script, but I have run into a strange error.
The following code works when I run it from the shell, but not when it is run from a script:
$UserCredential = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionURI http://servername/Powershell/ -Authentication Kerberos -Credential $UserCredential -AllowRedirection
Import-PSSession $Session
When I run it in a script with a Param() block on the first line, it fails with the following error:
Import-PSSession: Cannot bind argument to parameter 'Path' becuase it is an empty string.
I can get the Import-PSSession to work if I remove my Param() block, but I'm not sure how to accept command-line arguments for my script otherwise. How can I keep the Param() block (or more generally, accept command-line arguments) and still be able to import the PS session?
I'm using Powershell v2 on a Windows 2008 R2 server trying to connect to a 2010 Exchange server.
Update:
I have a script named ManageUser.ps1 that I run from a Powershell prompt like
.\ManageUser.ps1 -disableUser -username someuser
The script starts like this:
Param(
[switch]$disableUser,
[string]$username
)
$UserCredential = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionURI http://servername/Powershell/ -Authentication Kerberos -Credential $UserCredential -AllowRedirection
Import-PSSession $Session
#more stuff past here...
It is failing on the Import-PSSession command. But, if I remove the whole Param(...), the session import works. I hope this is enough for you to understand it!
Your script works fine on it's own and also when called from within another script:
& 'C:\Scripts\ManageUser.ps1' -disableUser -username "foo"
Get-Mailbox -resultsize 5 | ConvertTo-Csv -NoTypeInformation | Out-File C:\Scripts\mytest.csv
Subsequent runs will get the import error/warning due to not having -allowclobber as mentioned by #SamuelWarren...
In your case (at least when initially writing the question long ago) the error was due to another variable that you haven't mentioned here. It's likely you fixed that after the first run, and then subsequent tests were showing the AllowClobber error.
Also worth noting (for anybody who comes across this in the future) to check the path of the file you are calling. Just because you try to use a relative path .\myfile.ps1 doesn't mean that PowerShell is currently looking in the right directory.
Check: $psscriptroot
Or Split-Path -Path $($global:MyInvocation.MyCommand.Path)

powershell function not working right when used in custom module

My function is simple, it connects you to an Office365 account:
Function Connect-O365 {
[CmdletBinding()]
Param()
$url = "https://ps.outlook.com/powershell"
$O365Credential = Get-Credential -Message "Enter your Office 365 Credentials"
$O365Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url -Credential $O365Credential -Authentication Basic -AllowRedirection
Import-PSSession -Session $O365Session -Prefix O365
}
When running from a custom module, the commands from the imported session are not imported, no message is returned back with any errors or anything.
However, if i copy/paste the same function to my powershell profile, or direct to the console, it works perfectly fine, the commands are successfully imported from the session.
Thoughts?
EDIT: My Module I am adding this function to is a simple .psm1 file with only two other unrelated functions in it, nothing too complex either.
modified the last line in my function to:
Import-Module (Import-PSSession -Session $O365Session) -Global -Prefix O365
This resolved my issue, it was that the module was not importing on my Import-Session

Commands from implicit remoting module not available when created from another module's function

I'm a beginner to advanced PowerShell techniques. I'm attempting to write my own PS module. Hopefully I can properly articulate my problem.
Background:
I've created a module of all of my commonly used functions, called MyTools. The PSM1 file simply dot sources other PS1 files in the same module folder. At the end of the module, I export the module members with Export-ModuleMember -Function * -Alias * -Cmdlet *. (I've also created a manifest, but I'm not sure that matters for my problem.)
One of these functions (called Connect-O365) is defined in one of the dot-sourced PS1 files. The function automates the connection to Office 365 remote powershell. The key parts of the function simply do:
$O365PS = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $O365URL -Credential $Credential -Authentication Basic -AllowRedirection -Name "O365-$($Credential.UserName)" #-WarningAction SilentlyContinue
Import-PSSession -Session $O365PS -Prefix $CommandPrefix -WarningAction SilentlyContinue -DisableNameChecking
Connect-MsolService -Credential $Credential
"Connect-MSOLService" is from a different module, MSOnline.
Problem: When I open PowerShell, load my module via Import-Module MyTools, then run Connect-O365, the session is created. I see that the implicit remoting module is created and the commands are being received from the session (at least that's what the progress bar tells me).
However, none of those Office 365 commands from the remote session are available once it's done. The commands loaded from the local Connect-MSOLservice are available, though.
If I dot-source the individual PS1 file that defines the Connect-O365 function, the function works fine. I just have a problem when loading the function definition from my custom module. In other words, if I call the function when its loaded by the module, the exported commands are not available. Yet if I load the function by calling the PS1 file, it works fine.
Is this a problem of scope or that the imported commands were not exported by the module when the MyTools module was initially loaded (Export-ModuleMember)?
EDITS:
I'm using PowerShell 4.0
Additional screenshot showing the commands that are loaded, yet are not available after the function finishes.
Per this question from 2012 (which my question is remarkably similar to): Import-Pssession is not importing cmdlets when used in a custom module
It suggests wrapping the function with another Import-Module (Connect-O365) -Global.
I've tried this both at the PS prompt (once the MyTools module is loaded), as well as within the function itself using:
Import-Module (Import-PSSession -Session $O365PS -Prefix $CommandPrefix -WarningAction SilentlyContinue -DisableNameChecking -AllowClobber) -Global
But neither worked.
Update [7/23] - Simple illustration of problem added below
This function is stored in a *.PSM1 module file (e.g. TestModule.psm1). The module is then loaded via "Import-Module TestModule"
Function ConnectToAD {
$Sess1 = New-PSSession -ComputerName DC01 -Credential (Get-Credential)
Invoke-Command -Session $Sess1 {Import-Module ActiveDirectory}
Import-PSSession $Sess1 -Prefix Remote -Module ActiveDirectory
}
Export-ModuleMember -Function ConnectToAD
Once the module is loaded, and the function is called, none of the "Remote"-prefixed commands work.
Quoting the answer from the other thread that BHall linked above since it worked for me:
"With some assistance from TechNet I was able to modify the script module so it worked the way I expected.
function Connect-O365 {
$o365cred = Get-Credential username#domain.onmicrosoft.com
$session365 = New-PSSession `
-ConfigurationName Microsoft.Exchange `
-ConnectionUri "https://ps.outlook.com/powershell/" `
-Credential $o365cred `
-Authentication Basic `
-AllowRedirection
Import-Module (Import-PSSession $session365 -AllowClobber) -Global
}
TechNet Post"
Can you try dot-sourcing the function execution?
. Connect-O365
This would execute the function in the current scope (just like dot-sourcing a script runs it in your own scope).
Import-module is scoped, so this makes some sense. :-)